package com.lhz.common.utils.task;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.support.CronExpression;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * cron表达式工具类
 *
 * @author lihuazhi
 */
@Slf4j
public class CronUtils {
    /**
     * 返回一个布尔值代表一个给定的Cron表达式的有效性
     *
     * @param cronExpression Cron表达式
     * @return boolean 表达式是否有效
     */
    private static boolean isValid(String cronExpression) {
        try {
            CronExpression.parse(cronExpression);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 返回下一个执行时间根据给定的Cron表达式
     *
     * @param cronExpression Cron表达式
     * @param num            获取数量
     * @param format         是否格式化为字符串
     * @return Date 下次Cron表达式执行时间
     */
    public static Object getNextExecution(String cronExpression, int num, LocalDateTime currentDate, boolean format) {

        List<String> dateStrList = new ArrayList<>();
        List<LocalDateTime> dateList = new ArrayList<>();
        try {
            CronExpression csg = CronExpression.parse(cronExpression);
            // 近n次时间
            LocalDateTime nextDate = currentDate;
            for (int count = 1; count <= num; count++) {
                // 传入参数为计算下次时间点的开始时间
                nextDate = csg.next(nextDate);
                //进行格式化
                if (format) {
                    String dateStr = DateUtil.format(nextDate, "yyyy-MM-dd HH:mm:ss");
                    dateStrList.add(dateStr);

                    continue;
                }
                dateList.add(nextDate);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        // 返回数据
        return format ? dateStrList : dateList;
    }


    // 与当前传入时间对比，如果时间差小于1s则获取第二个时间，
    // 主要为了解决时间周期很短的任务会出现返回的下次执行时间还在周期内(主要是1S的情况)
    public static LocalDateTime nextCurrentTime(String cron) {
        long timeMillis = System.currentTimeMillis();
        //如果存在获取的新的下次执行时间和当前已执行的时间一致，则返回第二个执行时间
        List<LocalDateTime> execution = (List<LocalDateTime>) getNextExecution(cron, 2, LocalDateTime.now(), false);
        return execution.get(0);
    }
}
